
#include <iostream>
#include <fstream>
#include <vector>

#include "../mainctrl.h"
#include "../item/CItemMgr.h"
#include "../item/CScrollConfig.h"
#include "../storage/CUserStorage.h"
#include "../online/onlineuser.h"
#include "CDrugMgr.h"
#include "pb_cfg_drug.pb.h"
#include "MsgStorage.pb.h"
#include "MsgDrug.pb.h"

int CDrugMgr::Init(const char * sBuff)
{
    int iRet = _stDrugConfig.Init(sBuff);
    CHECK_RETURN(iRet);

    CRateTarget stDrop;
    stDrop._iMaxCount = CRateTarget::TARGET_INFINITY;

    stDrop._iTargetID = DRUG_PURIFY_SURPRISE_NONE;
    stDrop._iRate = DRUG_PURIFY_SURPRISE_RATE_NONE;
    _stPurifyRandom.Add(stDrop);

    stDrop._iTargetID = DRUG_PURIFY_SURPRISE_PURITY;
    stDrop._iRate = DRUG_PURIFY_SURPRISE_RATE_PURITY;
    _stPurifyRandom.Add(stDrop);

    stDrop._iTargetID = DRUG_PURIFY_SURPRISE_MONEY;
    stDrop._iRate = DRUG_PURIFY_SURPRISE_RATE_MONEY;
    _stPurifyRandom.Add(stDrop);

    return 0;
}

int CDrugMgr::CountSize()
{
    return _stDrugConfig.CountSize();
}

int CDrugMgr::LoadConfig(const char* szLogPath)
{
    int iRet = 0;

    if (szLogPath == NULL)
    {
        CT_ERROR(("Task Log Path is null"));
        return RET_SYSTEM_FAIL;
    }

    pb_cfg_drug stDrugPbCfg;
    std::fstream stFileInput(szLogPath, std::ios::in | std::ios::binary);
    if (!stDrugPbCfg.ParseFromIstream(&stFileInput))
    {
        CT_ERROR(("Failed to Parse drug!"));
        return RET_SYSTEM_FAIL;
    }

    for (int i = 0; i < stDrugPbCfg.drug_config_rows_size(); ++i)
    {
        const pb_cfg_drug_pb_cfg_drug_config_unit & stDrugPbCfgUnit
            = stDrugPbCfg.drug_config_rows(i);

        CDrugConfigData stConfigData;
        stConfigData._usDrugConfigID = (unsigned short)(stDrugPbCfgUnit.drug_id() & 0xFFFF);
        stConfigData._usScrollId = (unsigned short)(stDrugPbCfgUnit.scroll_id() & 0xFFFF);
        stConfigData._stKey._ucDrugAttr = (unsigned char)(stDrugPbCfgUnit.attr_type() & 0xFF);
        stConfigData._stKey._ucDrugLevel = (unsigned char)(stDrugPbCfgUnit.drug_level() & 0xFF);

        iRet = _stDrugConfig.AddDrugConfigData(stConfigData);
        if (iRet)
        {
            CT_ERROR(("Add drug config data failed.iRet: %u, drugid: %u.", iRet, stConfigData._usDrugConfigID));
            return iRet;
        }
    }

    for (int i = 0; i < stDrugPbCfg.synthe_drug_config_rows_size(); ++i)
    {
        const pb_cfg_drug_pb_cfg_synthe_drug_config_unit & stDrugPbCfgUnit
            = stDrugPbCfg.synthe_drug_config_rows(i);

        CSyntheDrugConfig stConfigData;
        stConfigData._ucDrugCapacity = (unsigned char)(stDrugPbCfgUnit.drug_capacity() & 0xFF);
        stConfigData._ucAttrAddition = (unsigned char)(stDrugPbCfgUnit.attr_addition() & 0xFF);
        stConfigData._stSyntheKey._ucStage = (unsigned char)(stDrugPbCfgUnit.synthe_stage() & 0xFF);
        stConfigData._stSyntheKey._ucLevel = (unsigned char)(stDrugPbCfgUnit.drug_level() & 0xFF);

        iRet = _stDrugConfig.AddSyntheDrugCfg(stConfigData);
        if (iRet)
        {
            CT_ERROR(("Add drug make config data failed.iRet: %u, ucLevel: %u. ucStage: %u", iRet,
                        stConfigData._stSyntheKey._ucLevel, stConfigData._stSyntheKey._ucStage));
            return iRet;
        }
    }

    for (int i = 0; i < stDrugPbCfg.purify_drug_config_rows_size(); ++i)
    {
        const pb_cfg_drug_pb_cfg_purify_drug_config_unit & stDrugPbCfgUnit
            = stDrugPbCfg.purify_drug_config_rows(i);

        CPurifyDrugConfig stPurifyConfig;
        stPurifyConfig._stPurifyKey._ucStage = (unsigned char)(stDrugPbCfgUnit.purify_stage() & 0xFF);
        stPurifyConfig._stPurifyKey._ucLevel = (unsigned char)(stDrugPbCfgUnit.drug_level() & 0xFF);
        stPurifyConfig._ucAttrAddition = (unsigned char)(stDrugPbCfgUnit.attr_addition() & 0xFF);
        stPurifyConfig._usPotionId  = (unsigned short)(stDrugPbCfgUnit.potion_id() & 0xFFFF);
        stPurifyConfig._usNeedPotionCnt  = (unsigned short)(stDrugPbCfgUnit.need_potion_cnt() & 0xFFFF);
        stPurifyConfig._usNeedGold  = (unsigned short)(stDrugPbCfgUnit.need_gold() & 0xFFFF);
        stPurifyConfig._uiNeedSilver = (unsigned int)stDrugPbCfgUnit.need_silver();

        iRet = _stDrugConfig.AddPurifyDrugCfg(stPurifyConfig);
        if (iRet)
        {
            CT_ERROR(("Add drug purify config data failed.iRet: %u, ucLevel: %u. ucStage: %u", iRet,
                stPurifyConfig._stPurifyKey._ucLevel, stPurifyConfig._stPurifyKey._ucStage));
            return iRet;
        }
    }

    for (int i = 0; i < stDrugPbCfg.drug_inherit_rows_size(); ++i)
    {
        const pb_cfg_drug_pb_cfg_drug_inherit_unit & stDrugPbCfgUnit
            = stDrugPbCfg.drug_inherit_rows(i);

        CDrugInheritCfg stInheritConfig;
        stInheritConfig._ucLevel = (unsigned char)(stDrugPbCfgUnit.level() & 0xFF);
        stInheritConfig._iSynSilver = stDrugPbCfgUnit.syn_silver();
        stInheritConfig._iSynGold = stDrugPbCfgUnit.syn_gold();
        stInheritConfig._iPuriGold = stDrugPbCfgUnit.puri_gold();
        stInheritConfig._iPuriSilver = stDrugPbCfgUnit.puri_silver();

        iRet = _stDrugConfig.AddInheritCfg(stInheritConfig);
        if (iRet)
        {
            CT_ERROR(("Add drug config data failed.iRet: %u, ucLevel: %u.", iRet, stInheritConfig._ucLevel));
            return iRet;
        }
    }

    return 0;
}

CDrugConfigData & CDrugMgr::GetDrugConfigData(unsigned short usDrugId)
{
    return _stDrugConfig.GetDrugConfigData(usDrugId);
}

int CDrugMgr::GetSyntheDrugCfg(CDrugOperKey &stKey, CSyntheDrugConfig & stConfigData)
{
    return _stDrugConfig.GetSyntheDrugCfg(stKey, stConfigData);
}

int CDrugMgr::GetPurifyDrugCfg (CDrugOperKey &stKey, CPurifyDrugConfig & stConfigData)
{
    return _stDrugConfig.GetPurifyDrugCfg(stKey, stConfigData);
}

bool CDrugMgr::IsValidDrug (unsigned short usDrugId)
{
    return _stDrugConfig.IsValidDrug(usDrugId);
}

int CDrugMgr::GetDrugLevel (unsigned short usDrugId)
{
    CDrugConfigData & stConfigData = _stDrugConfig.GetDrugConfigData(usDrugId);

    return stConfigData._stKey._ucDrugLevel;
}

int CDrugMgr::GetAttrType (unsigned short usDrugId)
{
    CDrugConfigData & stConfigData = _stDrugConfig.GetDrugConfigData(usDrugId);

    return stConfigData._stKey._ucDrugAttr;
}

int CDrugMgr::SynthetizeDrug (CPlayerBaseInfo & stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData & stPlayerOnlineData,
                              MsgReqDrugMake & stReq, MsgAnsDrugMake & stAns)
{
    unsigned short usRoleId = stReq.role_id();
    unsigned short usDrugId = stReq.drug_id();
    int iMethod = stReq.method();

    CDrugData & stUserDrug = GetUserDrug(stPlayerDetailInfo, usRoleId);
    CSingleDrug & stSingleDrug = GetSingleDrug(stUserDrug, usDrugId);
    CDrugConfigData & stConfigData = GetDrugConfigData(usDrugId);
    CUserStorage & stUserStorage = stPlayerOnlineData._stUserStorage;

    //TASK #191::关闭魔药
    if (stConfigData._stKey._ucDrugLevel >= 8)  
    {
        return ERROR_SYS_NOT_OPEN;
    }

    if (stSingleDrug.IsSyntheFull())
    {
        return ERROR_DRUG_SYN_FULL;
    }

    CMainCtrl * pstMainCtrl = CMainCtrl::m_pstMain;
    int iCost;

    unsigned char ucUseScroll = 0;
    if (MAKE_DRUG_NORMAL == iMethod)
    {
        bool bStuffEnough = pstMainCtrl->m_stStorageMgr.IsScrollMaterialEnough(stPlayerOnlineData._stUserStorage, stConfigData._usScrollId);
        if (true != bStuffEnough)
        {
            return ERROR_SCROLL_MATERIAL_LACK;
        }

        ucUseScroll = SCROLL_USE_SILVER;
    }
    else
    {
        int iRet = pstMainCtrl->m_stStorageMgr.GetScrollGoldCost(stPlayerOnlineData._stUserStorage, stConfigData._usScrollId, iCost);
        CHECK_RETURN(iRet);

        if (stPlayerBaseInfo._iGold < iCost)
        {
            return ERROR_GOLD_LESS;
        }

        ucUseScroll = SCROLL_USE_GOLD;
    }

    CStorageGrid stScrollGrid;
    stScrollGrid._stKey._ucItemType = ITEM_TYPE_SCROLL;
    stScrollGrid._stKey._uiItemID = stConfigData._usScrollId;
    stScrollGrid._shCount = 0;

    int iRet;
    if (MAKE_DRUG_GOLD == iMethod)
    {
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubGold(stPlayerBaseInfo, OSS_MONEY_MODULE_25, iCost);
        CHECK_RETURN(iRet);
    }

    iRet = pstMainCtrl->m_stStorageMgr.MakeItem(stUserStorage, stScrollGrid, ucUseScroll, false);
    if (iRet)
    {
        CT_ERROR(("%d", iRet));
        return iRet;
    }

    CSyntheDrugConfig stSynConfigData;
    iRet = GetSyntheNextCfg (usDrugId, stSingleDrug, stSynConfigData);
    if (iRet)
    {
        CT_ERROR(("%d, %d, %d", iRet, usDrugId, stSingleDrug._shCapacity));
        return iRet;
    }

    stSingleDrug._shCapacity = stSynConfigData._ucDrugCapacity;

    CalcRoleAttr(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData, usRoleId);

    MsgTypeValuePair * pstAttr = stAns.mutable_cur_attr();
    pstAttr->set_type(stConfigData._stKey._ucDrugAttr);
    pstAttr->set_value(GetAttrOfSameType(stUserDrug, stConfigData._stKey._ucDrugAttr));

    //新手目标
    if (stSingleDrug.IsSyntheFull())
    {
        int iIndex = pstMainCtrl->m_stPlayerDetailEx1InfoHash.HashFind(stPlayerBaseInfo._uiGID);
        if (iIndex >= 0)
        {
            CPlayerDetailInfoEx1& stPlayerDetailEx1Info = pstMainCtrl->m_stPlayerDetailEx1InfoHash[iIndex];

            pstMainCtrl->m_stNewbieTaskMgr.Trigger(stPlayerDetailEx1Info._stNewbieTaskUserData, stPlayerBaseInfo._uiGID, NEWBIE_TASK_COND_7, 
                stConfigData._stKey._ucDrugLevel);
        }
    }

    //跑马灯
    if (stSingleDrug.IsSyntheFull() && stConfigData._stKey._ucDrugLevel >= 4)
    {
        MsgTips stTips;
        stTips.set_type(1027);

        stTips.add_tip_argument(CMainCtrl::m_pstMain->m_stRoleMgr.GetRoleName(stPlayerBaseInfo._uiGID));
        stTips.add_tip_argument(CTStringUtils::IntToString(stConfigData._stKey._ucDrugLevel));
        stTips.add_tip_argument(CTStringUtils::IntToString(stConfigData._stKey._ucDrugAttr));

        CMainCtrl::m_pstMain->SendOnlineTips(stTips);
    }

    return 0;
}

int CDrugMgr::PurifyDrug (CPlayerBaseInfo & stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData & stPlayerOnlineData,
                          MsgReqDrugMake & stReq, MsgAnsDrugMake & stAns)
{
    unsigned short usRoleId = stReq.role_id();
    unsigned short usDrugId = stReq.drug_id();
    int iMethod = stReq.method();

    CDrugData & stUserDrug = GetUserDrug(stPlayerDetailInfo, usRoleId);
    CSingleDrug & stSingleDrug = GetSingleDrug(stUserDrug, usDrugId);
    CDrugConfigData & stDrugCfg = GetDrugConfigData(usDrugId);
    CUserStorage & stUserStorage = stPlayerOnlineData._stUserStorage;

    //判断背包和仓库中是否有提纯剂
    CPurifyDrugConfig stConfigData;
    int iRet = GetPurifyDrugConfig(stDrugCfg._stKey._ucDrugLevel, stSingleDrug, stConfigData);
    CHECK_RETURN(iRet);

    if (stSingleDrug.IsPurifyFull())
    {
        return 0;
    }

    CMainCtrl * pstMainCtrl = CMainCtrl::m_pstMain;
    int iItemCnt = pstMainCtrl->m_stStorageMgr.GetItemCount(stUserStorage, ITEM_TYPE_MATERIAL, stConfigData._usPotionId);
    if (iItemCnt < stConfigData._usNeedPotionCnt)
    {
        return ERROR_DRUG_LACK_POTION;
    }

    unsigned char ucSuprise;
    iRet = pstMainCtrl->m_stDrugMgr.GetPurifySurprise(ucSuprise);
    CHECK_RETURN(iRet);

    int iCost = 0;
    if (MAKE_DRUG_NORMAL == iMethod)
    {
        iCost = stConfigData._uiNeedSilver;
        if (stPlayerBaseInfo._i64Silver < iCost)
        {
            return ERROR_SILVER_LESS;
        }

        iRet = pstMainCtrl->m_stStorageMgr.TakeOutItem(stUserStorage, ITEM_TYPE_MATERIAL, stConfigData._usPotionId,
                                                        stConfigData._usNeedPotionCnt);
        CHECK_RETURN(iRet);
    }
    else
    {
        iCost = stConfigData._usNeedGold;
        if (stPlayerBaseInfo._iGold < iCost)
        {
            return ERROR_GOLD_LESS;
        }
    }

    switch (ucSuprise)
    {
    case  DRUG_PURIFY_SURPRISE_PURITY:
        {
            stSingleDrug.AddPurify(DRUG_ADD_SURPRISE_PURITY_PERCENT);
        }
        break;

    case DRUG_PURIFY_SURPRISE_MONEY:
        {
            iCost = iCost * 0.8;
        }
        break;
    }

    if (MAKE_DRUG_NORMAL == iMethod)
    {
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubSilver(stPlayerBaseInfo, iCost, 0);
    }
    else
    {
        iRet = CMainCtrl::m_pstMain->m_stItemMgr.SubGold(stPlayerBaseInfo, OSS_MONEY_MODULE_26, iCost);
        CHECK_RETURN(iRet);
    }

    CalcRoleAttr(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData, usRoleId);
    stAns.set_surprise(ucSuprise);
    MsgTypeValuePair * pstAttr = stAns.mutable_cur_attr();
    pstAttr->set_type(stDrugCfg._stKey._ucDrugAttr);
    pstAttr->set_value(GetAttrOfSameType(stUserDrug, stDrugCfg._stKey._ucDrugAttr));
    return 0;
}

int CDrugMgr::GetPurifySurprise (unsigned char & ucSurprise)
{
    CRateTarget stDrop;

    int iRet = _stPurifyRandom.DropOne(stDrop);
    if (iRet)
    {
        return ERROR_DRUG_DROP_SURPRISE;
    }

    ucSurprise = stDrop._iTargetID;

    return 0;
}

int CDrugMgr::GetSingleDrug(CDrugData & stUserDrug, unsigned short usDrugId, CSingleDrug & stSingleDrug)
{
    if(!IsValidDrug(usDrugId))
    {
        return ERROR_DRUG_ROLE_ID_INVALID;
    }

    stSingleDrug = stUserDrug._astDrugData[usDrugId - 1];
    return 0;
}

CSingleDrug & CDrugMgr::GetSingleDrug(CDrugData & stUserDrug, unsigned short usDrugId)
{
    return stUserDrug._astDrugData[usDrugId - 1];
}

int CDrugMgr::GetPurifyDrugConfig (unsigned char ucLevel, CSingleDrug & stSingleDrug, CPurifyDrugConfig  & stConfigData)
{
    CDrugOperKey stKey;
    stKey._ucLevel = ucLevel;
    stKey._ucStage = stSingleDrug.GetPurifyStage();

    int iRet = _stDrugConfig.GetPurifyDrugCfg(stKey, stConfigData);
    CHECK_RETURN(iRet);

    return 0;
}

//银币最多传承一半属性
int CDrugMgr::GetInheritCapacity (int iSrcCapacity, int iDstCapacity)
{
    short shValue = iSrcCapacity / 2;
    if (iDstCapacity < shValue)
    {
        CSingleDrug stDrug;
        stDrug._shCapacity = shValue;

        //如果未到提纯阶段, 需要修正合成的百分比,以便计算属性
        if (!stDrug.IsSyntheFull())
        {
            shValue = _stDrugConfig.GetSynFloorCapacity(shValue);
        }
    }
    else
    {
        shValue = iDstCapacity;
    }

    return shValue;
}

void CDrugMgr::GetAddCapacity (CSingleDrug & stFromDrug, CSingleDrug & stToDrug, int & iSynthAdd, int & iPuriAdd)
{
    iSynthAdd = 0;
    iPuriAdd = 0;
    if (stToDrug._shCapacity > stFromDrug._shCapacity)
    {
        if (stToDrug.IsSyntheFull())
        {
            //计算增加的提纯纯度
            if (stFromDrug.IsSyntheFull())
            {
                iSynthAdd = 0;
                iPuriAdd = stToDrug._shCapacity - stFromDrug._shCapacity;
            }
            else
            {
                iSynthAdd = MAX_DRUG_CAPACITY - stFromDrug._shCapacity;
                iPuriAdd = stToDrug._shCapacity - MAX_DRUG_CAPACITY;
            }
        }
        else
        {
            iSynthAdd = stToDrug._shCapacity - stFromDrug._shCapacity;
            iPuriAdd = 0;
        }
    }
}


int CDrugMgr::GetInheritCost (CDrugData stSrcUserDrug, CDrugData stDstUserDrug, int & iSilver, int & iGold)
{
    CDrugData stTmpDrug;
    stTmpDrug = stDstUserDrug;

    int iInheritValue = 0;
    ChangeInheritDrugData(stSrcUserDrug, stTmpDrug, false, iInheritValue);

    iSilver = 0;
    iGold = 0;
    unsigned char ucDrugLevel = 0;
    unsigned short usDrugId = 0;

    int iSynthAdd = 0;
    int iPuriAdd = 0;
    for (int i = 0; i < stSrcUserDrug._astDrugData.Size(); i++)
    {
        CSingleDrug & stSrcDrug = stSrcUserDrug._astDrugData[i];
        CSingleDrug & stSilverDrug = stTmpDrug._astDrugData[i];
        CSingleDrug & stDstDrug = stDstUserDrug._astDrugData[i];

        usDrugId = i + 1;
        if (!IsValidDrug(usDrugId))
        {
            CT_ERROR(("%d", usDrugId));
            continue;
        }

        ucDrugLevel = GetDrugLevel(usDrugId);
        CDrugInheritCfg & stCfg = _stDrugConfig.GetInheritCfg(ucDrugLevel);

        //银币传承价格
        if (stSilverDrug._shCapacity > stDstDrug._shCapacity)
        {
            GetAddCapacity (stDstDrug, stSilverDrug, iSynthAdd, iPuriAdd);
            iSilver += (iSynthAdd * stCfg._iSynSilver + iPuriAdd * stCfg._iPuriSilver);
        }

        //金币传承价格
        if (stSrcDrug._shCapacity > stDstDrug._shCapacity)
        {
            GetAddCapacity (stDstDrug, stSrcDrug, iSynthAdd, iPuriAdd);
            iGold += ((iSynthAdd * stCfg._iSynGold + iPuriAdd * stCfg._iPuriGold) / COMM_MOD) ;
        }
    }

    return 0;
}

int CDrugMgr::InheritDrug (CDrugData & stSrcDrug, CDrugData & stDstDrug, bool bCostGold)
{   
    int iRet = CheckBeforeInherit(stSrcDrug, stDstDrug, bCostGold);
    CHECK_RETURN(iRet);

    int iInheritValue = 0;
    ChangeInheritDrugData(stSrcDrug, stDstDrug, bCostGold, iInheritValue);

    return RET_OK;
}

void CDrugMgr::ChangeInheritDrugData (CDrugData & stSrcDrug, CDrugData & stDstDrug, bool bCostGold, int & iInheritValue)
{
    for (int i = 0; i < stDstDrug._astDrugData.Size(); i++)
    {
        CSingleDrug & stSrcSingleDrug = stSrcDrug._astDrugData[i];
        CSingleDrug & stDstSingleDrug = stDstDrug._astDrugData[i];

        short shSrcCap = stSrcSingleDrug._shCapacity;
        short shDstCap  = stDstSingleDrug._shCapacity;

        if (shDstCap < shSrcCap)
        {
            if (bCostGold)   //金币传承全部属性
            {
                iInheritValue += (shSrcCap - shDstCap);
                stDstSingleDrug._shCapacity = stSrcSingleDrug._shCapacity;
            }
            else
            {
                stDstSingleDrug._shCapacity = GetInheritCapacity (shSrcCap, shDstCap);
                iInheritValue += (stDstSingleDrug._shCapacity - shDstCap);                
            }
        }
    }

    stSrcDrug.SetInherit();
    stDstDrug.SetBeInherit();
}

int CDrugMgr::CheckBeforeInherit (CDrugData stSrcDrug, CDrugData stDstDrug, bool bCostGold)
{
    if (false == stSrcDrug.CanInherit()) 
    {
        return ERROR_DRUG_INHERIT_ALREADY;
    }

    if (false == stDstDrug.CanBeInherit())
    {
        return ERROR_DRUG_BEINHET_ALREADY;
    }

    int iInheritValue = 0;

    //计算传承获得的属性
    ChangeInheritDrugData(stSrcDrug, stDstDrug, bCostGold, iInheritValue);

    if (iInheritValue <= 0)
    {
        return ERROR_DRUG_INHERIT_NULL;
    }
    
    return RET_OK;
}

int CDrugMgr::GetSingleAttr (unsigned short usDrugId, CSingleDrug & stSingleDrug, CAttrPair & stAttr)
{
    stAttr._ucType = GetAttrType(usDrugId);
    stAttr._iValue = 0;

    int iAttr = 0;
    int iRet = _stDrugConfig.GetSyntheAttr(usDrugId, stSingleDrug._shCapacity, iAttr);
    CHECK_RETURN(iRet);

    stAttr._iValue += iAttr;

    iRet = _stDrugConfig.GetPurifyAttr(usDrugId, stSingleDrug._shCapacity, iAttr);
    CHECK_RETURN(iRet);

    stAttr._iValue += iAttr;
    return 0;
}

int CDrugMgr::GetDrugTotalAttr (CDrugData & stUserDrug, CPlayerAttr & stTotalAttr)
{
    stTotalAttr.Clear();
    for (unsigned short usDrugId = 1; usDrugId <= MAX_DRUG_CONFIG_ID; usDrugId++)
    {
        CAttrPair stAttr;
        CSingleDrug & stSingleDrug = GetSingleDrug(stUserDrug, usDrugId);
        int iRet = GetSingleAttr(usDrugId, stSingleDrug, stAttr);
        if (iRet)
        {
            CT_ERROR(("%d, %d", usDrugId, stSingleDrug._shCapacity));
        }

        stTotalAttr.AddAttr(stAttr._ucType, stAttr._iValue);
    }

    return 0;
}

int CDrugMgr::GetAttrOfSameType (CDrugData & stUserDrug, unsigned char ucAttrType)
{
    int iAttr = 0;
    for (unsigned short usDrugId = 1; usDrugId <= MAX_DRUG_CONFIG_ID; usDrugId++)
    {
        if (ucAttrType != GetAttrType(usDrugId))
        {
            continue;
        }

        CAttrPair stAttr;
        CSingleDrug & stSingleDrug = GetSingleDrug(stUserDrug, usDrugId);
        int iRet = GetSingleAttr(usDrugId, stSingleDrug, stAttr);
        if (iRet)
        {
            CT_ERROR(("%d, %d", usDrugId, stSingleDrug._shCapacity));
        }

        iAttr +=  stAttr._iValue;
    }

    return iAttr;
}

int CDrugMgr::GetDrugAttr (CPlayerDetailInfo& stPlayerDetailInfo, unsigned short usRoleId, CPlayerAttr & stPlayerAttr)
{
    int iRet = CheckRoleId(stPlayerDetailInfo, usRoleId);
    CHECK_RETURN(iRet);

    CDrugData & stUserDrug = GetUserDrug (stPlayerDetailInfo, usRoleId);

    CPlayerAttr stDrugAttr;
    iRet = GetDrugTotalAttr (stUserDrug, stDrugAttr);
    CHECK_RETURN(iRet);

    int aiAttr[MAX_DRUG_TYPE] = {BASE_ATTR_INT, BASE_ATTR_VIT, BASE_ATTR_STR, BASE_ATTR_AGI};
    for (int i = 0; i < MAX_DRUG_TYPE; i++)
    {
        stPlayerAttr.AddAttr(aiAttr[i], stDrugAttr.GetAttr(aiAttr[i]));
    }    

    return 0;
}

int CDrugMgr::GetDrugMakeInfo(CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData & stPlayerOnlineData,
                              unsigned short usRoleId, unsigned short usDrugId, MsgAnsDrugMakeInfo & stAns)
{
    CMainCtrl * pstMainCtrl = CMainCtrl::m_pstMain;
    int iGoldCost = 0;
    int iSilverCost = 0;
    int iRet = 0;

    //调用处保证了参数的有效性.

    CDrugConfigData & stConfigData = GetDrugConfigData(usDrugId);
    CDrugData & stUserDrug = GetUserDrug(stPlayerDetailInfo, usRoleId);

    CSingleDrug stSingleDrug;
    iRet = pstMainCtrl->m_stDrugMgr.GetSingleDrug(stUserDrug, usDrugId, stSingleDrug);
    CHECK_RETURN(iRet);

    stAns.set_gid(stPlayerDetailInfo._uiGID);
    stAns.set_roleid(usRoleId);
    stAns.set_drug_id(usDrugId);

    MsgTypeValuePair stDrugAttr;
    stDrugAttr.set_type(stConfigData._stKey._ucDrugAttr);
    if (!stSingleDrug.IsSyntheFull())
    {
        MsgScrollDetailInfo stScrollDetail;
        iRet = pstMainCtrl->m_stStorageMgr.GetScrollDetailInfo(stPlayerOnlineData, stConfigData._usDrugConfigID, stScrollDetail);
        if (iRet)
        {
            CT_ERROR(("DRUG: Get drug synthe scroll detail info failed. iRet: %u, usDrugId: %u, sroll id: %u.",
                iRet, stConfigData._usDrugConfigID, stConfigData._usScrollId));
            return iRet;
        }

        iRet = pstMainCtrl->m_stStorageMgr.GetScrollGoldCost(stPlayerOnlineData._stUserStorage, stConfigData._usScrollId, iGoldCost);
        CHECK_RETURN(iRet);

        *(stAns.mutable_items()) = stScrollDetail.items();

        CSyntheDrugConfig stSynConfigData;
        iRet = _stDrugConfig.GetSyntheCfg(usDrugId, stSingleDrug._shCapacity, stSynConfigData);
        CHECK_RETURN(iRet);

        stDrugAttr.set_value(stSynConfigData._ucAttrAddition);
        *(stAns.mutable_cur_stage_attr()) = stDrugAttr;
        stAns.set_cur_stage_percent(stSynConfigData._ucDrugCapacity);

        iRet = GetSyntheNextCfg (usDrugId, stSingleDrug, stSynConfigData);
        CHECK_RETURN(iRet);

        if (!stSingleDrug.IsSyntheFull())
        {
            stDrugAttr.set_value(stSynConfigData._ucAttrAddition);
            *(stAns.mutable_next_stage_attr()) = stDrugAttr;
            stAns.set_next_stage_percent(stSynConfigData._ucDrugCapacity);
        }

        stAns.set_gold_cost(iGoldCost);
    }
    else if (!stSingleDrug.IsPurifyFull())
    {
        CPurifyDrugConfig stPurifyConfig;
        iRet = pstMainCtrl->m_stDrugMgr.GetPurifyDrugConfig(stConfigData._stKey._ucDrugLevel,
                                                            stSingleDrug, stPurifyConfig);
        CHECK_RETURN(iRet);

        iGoldCost = stPurifyConfig._usNeedGold;
        iSilverCost = stPurifyConfig._uiNeedSilver;

        int iSynthAttr = 0;
        iRet = _stDrugConfig.GetSyntheAttr(usDrugId, stSingleDrug._shCapacity, iSynthAttr);
        CHECK_RETURN(iRet);

        int iPuriAttr = 0;
        iRet = _stDrugConfig.GetPurifyAttr(stConfigData._stKey._ucDrugLevel, stSingleDrug._shCapacity, iPuriAttr);
        CHECK_RETURN(iRet);

        stDrugAttr.set_value(iSynthAttr + iPuriAttr);    //已经获得的属性
        *(stAns.mutable_cur_stage_attr()) = stDrugAttr;
        stAns.set_cur_stage_percent(stSingleDrug._shCapacity);

        stDrugAttr.set_value(iSynthAttr + stPurifyConfig._ucAttrAddition);    //提纯满时的属性
        *(stAns.mutable_next_stage_attr()) = stDrugAttr;
        stAns.set_next_stage_percent((stSingleDrug.GetPurifyStage() + 1)*MAX_PURIFY_PER_LEVEL + MAX_DRUG_CAPACITY);

        int iItemCount;
        iItemCount = pstMainCtrl->m_stStorageMgr.GetItemCount(stPlayerOnlineData._stUserStorage, ITEM_TYPE_MATERIAL,
                                                              stPurifyConfig._usPotionId);

        MsgItemSynInfo * pstPurifyPotion;
        pstPurifyPotion = stAns.add_items();
        pstPurifyPotion->set_item_type(ITEM_TYPE_MATERIAL);
        pstPurifyPotion->set_item_cfg_id(stPurifyConfig._usPotionId);
        pstPurifyPotion->set_need_item_cnt(stPurifyConfig._usNeedPotionCnt);
        pstPurifyPotion->set_cur_item_cnt(iItemCount);

        CInstanceId stInstanceId;
        pstMainCtrl->m_stInstanceMgr.GetDropInstanceID(ITEM_TYPE_MATERIAL, stPurifyConfig._usPotionId,
            stPlayerOnlineData._stUserInstance._stInstanceData._stHasOpenedInstanceData, stInstanceId);
        pstPurifyPotion->set_instance_id(stInstanceId._usInstanceID);
        pstPurifyPotion->set_instance_type(stInstanceId._ucInstanceType);

        stAns.set_gold_cost(iGoldCost);
        stAns.set_silver_cost(iSilverCost);
    }
    else
    {
        stAns.set_cur_stage_percent(stSingleDrug._shCapacity);
    }

    return 0;
}


int CDrugMgr::GetRoleDrugInfo(CPlayerDetailInfo& stPlayerDetailInfo, unsigned short usRoldId, MsgAnsRoleDrugInfo & stAns)
{
    int iRet = CheckRoleId(stPlayerDetailInfo, usRoldId);
    CHECK_RETURN(iRet);

    CDrugData & stUserDrug = GetUserDrug(stPlayerDetailInfo, usRoldId);

    CPlayerAttr stDrugAttr;
    iRet = GetDrugTotalAttr(stUserDrug, stDrugAttr);
    CHECK_RETURN (iRet);

    GetAttrPbMsg(stDrugAttr, *(stAns.mutable_total_attrs()));

    for (unsigned short usDrugId = 1; usDrugId <= MAX_DRUG_CONFIG_ID; usDrugId++)
    {
        MsgSingleDrug *pstSingleDrug = stAns.add_drugs();
        pstSingleDrug->set_drug_id(usDrugId);
        pstSingleDrug->set_drug_capacity(GetCapacityPercent(stUserDrug, usDrugId));
    }

    if (0 != usRoldId)
    {
        stAns.set_can_inherit(stUserDrug.CanInherit());
        if (stUserDrug.CanInherit())
        {
            for (int i = 0; i < stPlayerDetailInfo._stUserPartner._astActData.Size(); i++)
            {
                CPartnerActData & stActData = stPlayerDetailInfo._stUserPartner._astActData[i];
                if (stActData._shResID != usRoldId
                    && (true == stActData._stDrugData.CanBeInherit()))
                {
                    stAns.add_partners(stActData._shResID);
                }
            }
        }
    }

    return 0;
}


int CDrugMgr::GetCapacityPercent (CDrugData & stSrcDrug, unsigned short usDrugId)
{
    CSingleDrug stSingleDrug;
    int iRet = GetSingleDrug(stSrcDrug, usDrugId, stSingleDrug);
    if (iRet)
    {
        CT_ERROR(("%d, %d", usDrugId, iRet));
        return 0;
    }

    return stSingleDrug._shCapacity;
}


CDrugData & CDrugMgr::GetUserDrug(CPlayerDetailInfo& stPlayerDetailInfo, unsigned short usRoleId)
{
    if (0 == usRoleId)
    {
        return stPlayerDetailInfo._stDrugData;
    }
    else
    {
        int iIndex = stPlayerDetailInfo._stUserPartner.FindActData(usRoleId);
        CPartnerActData & stPartnerData = stPlayerDetailInfo._stUserPartner.GetPartnerActData(iIndex);
        return stPartnerData._stDrugData;
    }
}

int CDrugMgr::CheckRoleId (CPlayerDetailInfo& stPlayerDetailInfo, unsigned short usRoleId)
{
    if (0 != usRoleId)
    {
        int iIndex = stPlayerDetailInfo._stUserPartner.FindActData(usRoleId);
        if (iIndex < 0)
        {
            return ERROR_DRUG_ROLE_ID_INVALID;
        }
    }

    return RET_OK;
}


void CDrugMgr::CalcRoleAttr(CPlayerBaseInfo & stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData & stPlayerOnlineData, unsigned short usRoleId)
{
    if (0 == usRoleId)
    {
        //重新计算主角属性
        CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_ROLE_ATTR);
    }
    else
    {
        //重新计算伙伴属性
        CMainCtrl::m_pstMain->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_PARTNER_ATTR, usRoleId);
    }
}


int CDrugMgr::GetSyntheNextCfg (unsigned short usDrugId, CSingleDrug & stSingleDrug, CSyntheDrugConfig & stSynConfigData)
{
    int iRet = _stDrugConfig.GetSyntheCfg(usDrugId, stSingleDrug._shCapacity, stSynConfigData);
    CHECK_RETURN(iRet);

    if (!stSingleDrug.IsSyntheFull())
    {
        CDrugOperKey stKey;
        stKey._ucLevel = GetDrugLevel(usDrugId);
        stKey._ucStage = stSynConfigData._stSyntheKey._ucStage + 1;
        iRet = GetSyntheDrugCfg(stKey, stSynConfigData);
        CHECK_RETURN(iRet);
    }

    return 0;
};

int CDrugMgr::GetInheritInfo (CDrugData stSrcDrug, CDrugData stDstDrug, bool bUseGold, MsgInheritInfo & stInfo)
{
    CPlayerAttr stAttr;
    int iRet = GetDrugTotalAttr (stDstDrug, stAttr);
    CHECK_RETURN(iRet);

    GetAttrPbMsg(stAttr, *(stInfo.mutable_org_attr()));   //接受传承者的原始属性

    int iInheritValue = 0;
    ChangeInheritDrugData(stSrcDrug, stDstDrug, bUseGold, iInheritValue);

    iRet = GetDrugTotalAttr (stDstDrug, stAttr);
    CHECK_RETURN(iRet);

    GetAttrPbMsg(stAttr, *(stInfo.mutable_dst_attr()));   //传承后的总属性

    return 0;
}


int CDrugMgr::GetDrugInheritInfo (CPlayerDetailInfo& stPlayerDetailInfo, MsgReqDrugInherit & stReq, MsgAnsDrugInherit & stInfo)
{
    unsigned short usSrcRoleId = (unsigned short)(stReq.src_role_id() & 0x7FFF);
    unsigned short usDstRoleId = (unsigned short)(stReq.dst_role_id() & 0x7FFF);

    CDrugData & stSrcDrug = GetUserDrug(stPlayerDetailInfo, usSrcRoleId);
    CDrugData & stDstDrug = GetUserDrug(stPlayerDetailInfo, usDstRoleId);

    int iNeedSilver;
    int iNeedGold;
    int iRet = GetInheritCost(stSrcDrug, stDstDrug, iNeedSilver, iNeedGold);
    CHECK_RETURN(iRet);

    MsgInheritInfo *pstInfo = stInfo.add_infos();
    pstInfo->set_type(MAKE_DRUG_GOLD);
    pstInfo->set_cost(iNeedGold);
    iRet = GetInheritInfo (stSrcDrug, stDstDrug, true, *pstInfo);
    CHECK_RETURN(iRet);

    pstInfo = stInfo.add_infos();
    pstInfo->set_type(MAKE_DRUG_NORMAL);
    pstInfo->set_cost(iNeedSilver);
    iRet = GetInheritInfo (stSrcDrug, stDstDrug, false, *pstInfo);
    CHECK_RETURN(iRet);

    return 0;
}

void CDrugMgr::GetAttrPbMsg(CPlayerAttr & stAttr, ::google::protobuf::RepeatedPtrField< ::MsgTypeValuePair > & stMsgAttr)
{
    int aiAttr[MAX_DRUG_TYPE] = {BASE_ATTR_INT, BASE_ATTR_VIT, BASE_ATTR_STR, BASE_ATTR_AGI};
    for (int i = 0; i < MAX_DRUG_TYPE; i++)
    {
        MsgTypeValuePair *pstAttrPair = stMsgAttr.Add();
        pstAttrPair->set_type(aiAttr[i]);
        pstAttrPair->set_value(stAttr.GetAttr(aiAttr[i]));
    }
}
